import datetime

from django.shortcuts import render
from django.http import JsonResponse
from apps.web.forms.issues import IssuesModelForm, IssuesReplyModelForm, InviteModelForm
from apps.web import models
from utils.pagination import Pagination
from django.views.decorators.csrf import csrf_exempt
from django.utils.safestring import mark_safe
import json
from utils.encrypt import uid
from django.urls import reverse
from django.db import transaction


class CheckBox():
    """
    筛选界面
    """

    def __init__(self, name, data_list, request):
        self.name = name
        self.data_list = data_list
        self.request = request

    def __iter__(self):
        for item in self.data_list:
            key = item[0]
            text = item[1]
            ck = ''

            # 判断当前用户的url,里面的参数，去给url加checked
            value_list = self.request.GET.getlist(self.name)
            if str(key) in value_list:
                ck = 'checked'
                value_list.remove(str(key))
            else:
                value_list.append(str(key))

            # 为自己生成url, 在当前url的基础上在增加一项
            # 拿到所有的？后面的参数
            query_dict = self.request.GET.copy()
            query_dict._mutable = True
            query_dict.setlist(self.name, value_list)
            if 'page' in query_dict:
                query_dict.pop('page')
            param_url = query_dict.urlencode()
            if param_url:
                url = '{}?{}'.format(self.request.path_info, param_url)
            else:
                url = self.request.path_info
            html = "<a class='cell' href='{url}'><input type='checkbox'  {ck} style='pointer-events:none;' /><label>{text}</label></a>".format(
                text=text, ck=ck, url=url)
            yield mark_safe(html)


class SelectBox(object):
    def __init__(self, name, data_list, request):
        self.name = name
        self.data_list = data_list
        self.request = request

    def __iter__(self):
        yield mark_safe('<select class="select2" multiple="multiple" style="width:100%">')
        for item in self.data_list:
            id = str(item[0])
            name = item[1]
            selected = ''
            # 获取当前url的所有参数
            value_list = self.request.GET.getlist(self.name)

            if id in value_list:
                selected = 'selected'
                value_list.remove(id)
            else:
                value_list.append(id)

            # 为自己生成url, 在当前url的基础上在增加一项
            # 拿到所有的？后面的参数
            query_dict = self.request.GET.copy()
            query_dict._mutable = True
            query_dict.setlist(self.name, value_list)
            if 'page' in query_dict:
                query_dict.pop('page')
            param_url = query_dict.urlencode()
            if param_url:
                url = '{}?{}'.format(self.request.path_info, param_url)
            else:
                url = self.request.path_info
            html = '<option value="{url}" {selected}>{name}</option>'.format(url=url, selected=selected, name=name)
            yield mark_safe(html)
        yield mark_safe('</select>')


def issues(request, project_id):
    if request.method == 'GET':

        # 筛选条件 根据用户get传参 status=1,issues_type=1, priority
        allow_filter_list = ['status', 'issues_type', 'priority', 'assign', 'attention']
        condition = {}
        for name in allow_filter_list:
            # 如果传的参数名（status=1&status=1）为多个，可以获取到多个值的列表
            value_list = request.GET.getlist(name)
            if not value_list:
                continue
            condition['{}__in'.format(name)] = value_list

        """
        condition = {
            'status__in': [1,],
        }
        """
        # 分页获取数据
        queryset = models.Issues.objects.filter(project_id=project_id).filter(**condition)  # 所有数据, 筛选数据
        # 分页组件
        page_obj = Pagination(
            current_page=request.GET.get('page'),
            all_count=queryset.count(),
            base_url=request.path_info,
            query_params=request.GET,
            per_page=5
        )

        # 拿到数据库的所有问题
        issues_obj_list = queryset[page_obj.start:page_obj.end]
        form = IssuesModelForm(request)
        # 查询问题类型
        pro_issues_type = models.IssuesType.objects.filter(project_id=project_id).values_list('id', 'title')
        project_total_user = [(request.tracer.project.creator_id, request.tracer.project.creator.username)]
        project_joinuser = models.ProjectUser.objects.filter(project_id=project_id).values_list('user_id',
                                                                                                'user__username')
        project_total_user.extend(project_joinuser)
        # 邀请用户modelform
        invite_form = InviteModelForm()
        context = {
            'form': form,
            'invite_form': invite_form,
            'issues_obj_list': issues_obj_list,
            'page_html': page_obj.page_html(),
            'status_filter': CheckBox('status', models.Issues.status_choices, request),
            'priority_filter': CheckBox('priority', models.Issues.priority_choices, request),
            'issues_type_filter': CheckBox('issues_type', pro_issues_type, request),
            'assign_filter': SelectBox('assign', project_total_user, request),
            'attention_filter': SelectBox('attention', project_total_user, request),
        }

        return render(request, 'web/issues.html', context)

    # post请求
    form = IssuesModelForm(request, data=request.POST)
    if form.is_valid():
        form.instance.project = request.tracer.project
        form.instance.creator = request.tracer.user
        form.save()
        return JsonResponse({'status': True})
    return JsonResponse({'status': False, 'error': form.errors})


def detail(request, project_id, issues_id):
    issues_obj = models.Issues.objects.filter(project_id=project_id, id=issues_id).first()
    form = IssuesModelForm(request, instance=issues_obj)
    return render(request, 'web/issues_detail.html', {'form': form, 'issues_obj': issues_obj})


@csrf_exempt
def record(request, project_id, issues_id):
    """初始化操作记录"""
    if request.method == 'GET':

        reply_list = models.IssuesReply.objects.filter(issues__project=request.tracer.project, issues_id=issues_id)
        # 将queryset(reply_list)转换为JSON
        data_list = []
        for row in reply_list:
            data = {
                'id': row.id,
                'reply_type_text': row.get_reply_type_display(),
                'context': row.content,
                'creator': row.creator.username,
                'datetime': row.create_datetime.strftime('%Y-%m-%d %H:%M'),
                'parent_id': row.reply_id,
                'parent_creator': row.reply.creator.username if row.reply else None,  # 添加父级评论用户名
            }
            data_list.append(data)

        return JsonResponse({'status': True, 'data': data_list})
    # post请求
    form = IssuesReplyModelForm(data=request.POST)
    if form.is_valid():
        form.instance.issues_id = issues_id
        form.instance.reply_type = 2
        form.instance.creator = request.tracer.user
        instance = form.save()
        info = {
            'id': instance.id,
            'reply_type_text': instance.get_reply_type_display(),
            'context': instance.content,
            'creator': instance.creator.username,
            'datetime': instance.create_datetime.strftime('%Y-%m-%d %H:%M'),
            'parent_id': instance.reply_id,
            'parent_creator': instance.reply.creator.username if instance.reply else None,  # 添加父级评论用户名
        }
        return JsonResponse({'status': True, 'data': info})
    return JsonResponse({'status': False, 'error': form.errors})


@csrf_exempt
def change(request, project_id, issues_id):
    """change事件，接受ajax请求回来的参数"""
    # 获取当前要操作的对象
    issues_obj = models.Issues.objects.filter(project_id=project_id, id=issues_id).first()
    post_dict = json.loads(request.body.decode('utf-8'))
    """{'name': 'issues_type', 'value': '1'}"""
    # print(post_dict)
    name = post_dict.get('name')
    value = post_dict.get('value')
    # 拿到当前的字段对象
    field_obj = models.Issues._meta.get_field(name)

    def creat_data(msg):
        # 保存到数据库
        new_obj = models.IssuesReply.objects.create(
            reply_type=1,
            issues=issues_obj,
            content=msg,
            creator=request.tracer.user,
        )
        new_data = {
            'id': new_obj.id,
            'reply_type_text': new_obj.get_reply_type_display(),
            'context': new_obj.content,
            'creator': new_obj.creator.username,
            'datetime': new_obj.create_datetime.strftime('%Y-%m-%d %H:%M'),
            'parent_id': new_obj.reply_id,
            'parent_creator': new_obj.reply.creator.username if new_obj.reply else None,  # 添加父级评论用户名
        }
        return new_data

    # 1.数据库更新
    # 1.1 文本字段
    if name in ['subject', 'desc', 'start_date', 'end_date']:
        if not value:
            if not field_obj.null:
                return JsonResponse({'status': False, 'error': '该项不能为空'})
            else:
                setattr(issues_obj, name, None)
                issues_obj.save()
                msg = '{}更新为空'.format(field_obj.verbose_name)
        else:
            setattr(issues_obj, name, value)
            issues_obj.save()
            msg = '{}更新为{}'.format(field_obj.verbose_name, value)

        return JsonResponse({'status': True, 'data': creat_data(msg)})

    # 1.2 fk（外键）字段
    if name in ['issues_type', 'module', 'parent', 'assign']:
        # 用户选择为空
        if not value:
            # 不允许为空的字段
            if not field_obj.null:
                return JsonResponse({'status': False, 'error': '该项不能为空'})
            # 允许为空
            else:
                setattr(issues_obj, name, None)
                issues_obj.save()
                msg = '{}更新为空'.format(field_obj.verbose_name)
        else:
            # 判断用户输入的值是关联表里面的值
            # 如果字段为指派assign时要判断是否为创建者或者参与这，而不是去关联的用户表里面查找
            # 拿到当前字段关联表里的对象
            if name == 'assign':
                # 是否时项目创建者
                # 当前项目创建者id
                if value == str(request.tracer.project.creator_id):
                    instance = request.tracer.project.creator
                else:
                    # 是否是项目参与者
                    pro_user = models.ProjectUser.objects.filter(project_id=project_id, user_id=value).first()
                    if pro_user:
                        instance = pro_user.user
                    else:
                        instance = None
                if not instance:
                    return JsonResponse({'status': False, 'error': '你选择的值不存在'})

                # setattr(issues_obj, name, instance)
                # issues_obj.save()
                # msg = '{}更新为{}'.format(field_obj.verbose_name, str(instance))
            else:
                instance = field_obj.remote_field.model.objects.filter(id=value, project_id=project_id).first()
                if not instance:
                    return JsonResponse({'status': False, 'error': '该项不存在，请重新选择'})

            setattr(issues_obj, name, instance)  # value为1/2/3 外键id
            issues_obj.save()
            msg = '{}更新为{}'.format(field_obj.verbose_name, str(instance))  # 根据value获取内容
        return JsonResponse({'status': True, 'data': creat_data(msg)})

    # 1.3 choice字段
    if name in ['status', 'priority', 'mode']:
        selected_text = None
        for key, text in field_obj.choices:
            if str(key) == value:
                selected_text = text
        if not selected_text:
            return JsonResponse({'status': False, 'error': '该项不存在，请重新选择'})
        setattr(issues_obj, name, value)
        issues_obj.save()
        msg = '{}更新为{}'.format(field_obj.verbose_name, selected_text)
        return JsonResponse({'status': True, 'data': creat_data(msg)})

    # 1.4 manytomany 字段
    if name == 'attention':
        # 关注者传过来是一个字典  {'name': 'attention', 'value': [1,2,3]}
        if not isinstance(value, list):
            return JsonResponse({'status': False, 'error': '数据格式错误'})
        # 数据为空
        if not value:
            issues_obj.attention.set([])
            issues_obj.save()
            msg = '{}更新为空'.format(field_obj.verbose_name)
            return JsonResponse({'status': True, 'data': creat_data(msg)})
        else:
            # value为关注者id
            # 判断id是否为项目成员 参与者，创建者
            # 获取当前项目所有成员
            user_dict = {str(request.tracer.project.creator_id): request.tracer.user.username, }
            project_user_list = models.ProjectUser.objects.filter(project_id=project_id)  # 参与者
            user_str = []
            for item in project_user_list:
                user_dict[str(item.user_id)] = item.user.username
            for user_id in value:
                username = user_dict.get(str(user_id))
                # 未拿到值
                if not username:
                    return JsonResponse({'status': False, 'error': '选择的用户非该项目成员，请重新选择'})
                user_str.append(username)
            # 数据库更新
            issues_obj.attention.set(value)
            issues_obj.save()
            msg = '{}更新为{}'.format(field_obj.verbose_name, ','.join(user_str))
            return JsonResponse({'status': True, 'data': creat_data(msg)})

    # 2.生成操作记录
    print(post_dict)
    return JsonResponse({'status': False, 'error': '非法操作'})


def invite(request, project_id):
    """
    生成邀请码
    :param request:
    :param project_id: 项目id
    :return:
    """
    form = InviteModelForm(data=request.POST)
    if form.is_valid():
        """
        限制项目创建者才能邀请成员
        创建一个随机验证码(邀请码), 
        保存到数据库
        """
        if request.tracer.user != request.tracer.project.creator:
            form.add_error('period', '只有项目创建者有权限邀请成员')
            return JsonResponse({'status': False, 'error': form.errors})
        invite_code = uid(request.tracer.user.mobile_phone)
        form.instance.project = request.tracer.project
        form.instance.creator = request.tracer.user
        form.instance.code = invite_code
        form.save()
        url = '{scheme}://{host}{path}'.format(
            scheme=request.scheme,
            host=request.get_host(),
            path=reverse('invite_join', kwargs={'invite_code': invite_code})
        )
        return JsonResponse({'status': True, 'data': url})
    return JsonResponse({'status': False, 'error': form.errors})


def join(request, invite_code):
    """加入项目"""
    # 拿到当前邀请码对象
    invite_obj = models.ProjectInvite.objects.filter(code=invite_code).first()
    # 判断邀请码是否存在
    if not invite_obj:
        return render(request, 'web/invite_join.html', {'error': '邀请码不存在'})
    # 判断是否为项目创建者
    if invite_obj.project.creator == request.tracer.user:
        return render(request, 'web/invite_join.html', {'error': '项目创建者无需再次加入项目'})
    # 判断该用户是否已经为项目成员
    exists = models.ProjectUser.objects.filter(project=invite_obj.project, user=request.tracer.user).exists()
    if exists:
        return render(request, 'web/invite_join.html', {'error': '已经为项目成员无需再次加入'})
    # 判断项目人数限制(当前项目创建者的价格策略)
    max_transaction = models.Transaction.objects.filter(user=invite_obj.project.creator, status=2).order_by(
        '-id').first()
    # 查看是否过期
    if max_transaction.price_policy.category == 1:
        max_member = max_transaction.price_policy.project_member
    else:
        if max_transaction.end_datetime < datetime.datetime.now():
            free_obj = models.PricePolicy.objects.filter(category=1).first()
            max_member = free_obj.project_member
        else:
            max_member = max_transaction.price_policy.project_member
    # if invite_obj.project.join_count + 1 > max_member:
    #     return render(request, 'web/invite_join.html', {'error': '项目已达到最大人数'})

    # 判断邀请码是否过期\
    current_time = datetime.datetime.now()
    limit_time = invite_obj.create_datetime + datetime.timedelta(minutes=invite_obj.period)
    if limit_time < current_time:
        return render(request, 'web/invite_join.html', {'error': '邀请码已过期'})

        # # 邀请码邀请的人数限制
        # if invite_obj.count:
        #     if invite_obj.use_count >= invite_obj.count:
        #         return render(request, 'web/invite_join.html', {'error': '该邀请码已经达到最大邀请人数'})
        #     invite_obj.use_count += 1
        #     invite_obj.save()
        #
        # # 校验完成，写入数据库
        # models.ProjectUser.objects.create(project=invite_obj.project, user=request.tracer.user)
        # # 更新项目参与人数
        # invite_obj.project.join_count = models.ProjectUser.objects.filter(project=invite_obj.project).count() + 1
        # invite_obj.project.save()
        # return render(request, 'web/invite_join.html', {'project': invite_obj.project})
        # # return redirect('project_list')

        # 使用事务和锁确保并发安全
    with transaction.atomic():
        # 锁定邀请码对象，防止并发修改 use_count
        invite_obj_locked = models.ProjectInvite.objects.select_for_update().get(id=invite_obj.id)
        # 锁定项目对象，防止并发修改 join_count
        project_locked = models.Project.objects.select_for_update().get(id=invite_obj.project.id)

        # 在锁内检查项目人数限制
        if project_locked.join_count + 1 > max_member:
            return render(request, 'web/invite_join.html', {'error': '项目已达到最大人数'})

        # 邀请码邀请的人数限制（在锁内检查）
        if invite_obj_locked.count:
            if invite_obj_locked.use_count >= invite_obj_locked.count:
                return render(request, 'web/invite_join.html', {'error': '该邀请码已经达到最大邀请人数'})

        # 校验完成，写入数据库
        models.ProjectUser.objects.create(project=project_locked, user=request.tracer.user)

        # 更新邀请码使用次数（使用锁定后的对象）
        if invite_obj_locked.count:
            invite_obj_locked.use_count += 1
            invite_obj_locked.save()

        # 更新项目参与人数（使用锁定后的对象）
        project_locked.join_count = models.ProjectUser.objects.filter(project=project_locked).count() + 1
        project_locked.save()

        return render(request, 'web/invite_join.html', {'project': project_locked})
